package com.flick.util;

import com.flick.annotation.IdName;
import com.flick.annotation.JoinPo;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class VoUtil {

    @SneakyThrows
    public static<T,V> V toVo(T t, Class<V> vo){
        V v = vo.newInstance();
        BeanUtils.copyProperties(t,v);
        v = annotations(t,v);
        return v;
    }

    @SneakyThrows
    public static<T,V> List<V> listToVo(List<T> list, Class<V> vo){
        List<V> vlist = new ArrayList<V>();
        if(list != null && !list.isEmpty()){
            for (T t: list) {
                V v = vo.newInstance();
                BeanUtils.copyProperties(t,v);
                v = annotations(t,v);
                vlist.add(v);
            }
        }
        return vlist;
    }

    @SneakyThrows
    public static<T,V> Page<V> pageToVo(Page<T> page, Class<V> vo){
        List<T> list = page.getContent();
        List<V> vlist = new ArrayList<V>();
        if(list != null && !list.isEmpty()){
            for (T t: list) {
                V v = vo.newInstance();
                BeanUtils.copyProperties(t,v);
                v = annotations(t,v);
                vlist.add(v);
            }
        }
        Page voPage = new PageImpl(vlist);
        return voPage;
    }

    public static<T,V> V annotations(T t,V v) throws Exception {
        Field[] fields = v.getClass().getDeclaredFields();
        for (Field field: fields) {
            //遍历结果中的IdName注解
            IdName idName = field.getAnnotation(IdName.class);
            if(idName != null){
                String key1 = field.getName();
                String keyMethodName = key1.substring(0, 1).toUpperCase().concat(key1.substring(1));
                Method method;
                try {
                    method = t.getClass().getMethod("get" + keyMethodName);
                } catch (NoSuchMethodException e) {
                    method = t.getClass().getMethod("is" + keyMethodName);
                }
                Object object = method.invoke(t);
                Map map = new HashMap();
                String id = idName.id();
                String name = idName.name();
                String idMethod = "get" + id.substring(0, 1).toUpperCase().concat(id.substring(1));
                String nameMethod = "get" + name.substring(0, 1).toUpperCase().concat(name.substring(1));
                if (object != null) map.put(String.valueOf(object.getClass().getMethod(idMethod).invoke(object)),String.valueOf(object.getClass().getMethod(nameMethod).invoke(object)));
                Class c2 = v.getClass();
                Method keyMethod = c2.getMethod("set" + keyMethodName, Map.class);
                keyMethod.invoke(v, map);
            }
            //遍历结果中的JoinPo注解
            JoinPo joinPo = field.getAnnotation(JoinPo.class);
            if(joinPo != null) {
                String key = field.getName();
                String value = joinPo.value();
                String[] values = value.split("[.]");
                if(values.length == 0){
                    values = new String[1];
                    values[0] = value;
                }
                Object resValue = getResValue(values,t);
                Class c2 = v.getClass();
                String keyMethodName = key.substring(0,1).toUpperCase().concat(key.substring(1));
                if(resValue != null) {
                    Method keyMethod = c2.getMethod("set" + keyMethodName, resValue.getClass());
                    keyMethod.invoke(v, resValue);
                }
            }
        }
        return v;
    }

    /**
     * 外键获取原po对象的属性
     * @param values 外键组合（如person.id，分成{"person","id"}
     * @param t 原po对象
     * @return 结果对象
     * @throws Exception
     */
    public static<T> Object  getResValue(String[] values,T t) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Object resValue = null;
        Class c1 = t.getClass();
        Object obj = t;
        for(int i=0; i < values.length; i++){
            String str = values[i];
            String methodName = str.substring(0,1).toUpperCase().concat(str.substring(1));
            if(i < values.length - 1 ) {
                Method method;
                try {
                    method = c1.getMethod("get" + methodName);
                } catch (NoSuchMethodException e) {
                    method = c1.getMethod("is" + methodName);
                }
                obj = method.invoke(obj);
                if(obj == null) {
                    resValue = null;
                    break;
                }
                c1 = obj.getClass();
            }
            else {
                Method method;
                try {
                    method = c1.getMethod("get" + methodName);
                } catch (NoSuchMethodException e) {
                    method = c1.getMethod("is" + methodName);
                }
                resValue = method.invoke(obj);
            }
        }
        return resValue;
    }


}
